package com.gitee.l0km.aocache;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.AbstractMap.SimpleImmutableEntry;
import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalNotification;

/**
 * {@link com.google.common.cache.RemovalListener}接口相关类的包装类<br>
 * 当 GUAVA 库的包被重定位时,通过此接口来提供兼容支持
 * 
 * @author guyadong
 *
 * @param <K>
 * @param <V>
 */
public interface AocacheRemovalListener<K, V> {

	void onRemoval(AocacheRemovalNotification<K, V> notification);

	/** {@link com.google.common.cache.RemovalNotification}的包装类 */
	public static final class AocacheRemovalNotification<K, V> extends SimpleImmutableEntry<K, V> {
		private final AocacheRemovalCause cause;

		/**
		 * 创建一个新的 {@link AocacheRemovalNotification} 实例。
		 * <p>
		 * 如果传入的 {@code notification} 为 {@code null}，则返回 {@code null}；<br>
		 * 否则，根据传入的 {@link RemovalNotification} 实例创建一个对应的
		 * {@link AocacheRemovalNotification} 实例。
		 * <p>
		 * 
		 * @param <K>          缓存键的类型。
		 * @param <V>          缓存值的类型。
		 * @param notification 用于创建 {@link AocacheRemovalNotification} 实例的
		 *                     {@link RemovalNotification} 实例。
		 * @return 一个新的 {@link AocacheRemovalNotification} 实例，如果传入的 {@code notification}
		 *         为 {@code null}，则返回 {@code null}。
		 */
		@SuppressWarnings("unchecked")
		public static <K, V> AocacheRemovalNotification<K, V> create(RemovalNotification<K, V> notification) {
			if(null != notification){
				K key;
				if(notification.getKey() instanceof InvokeKey){
					/**
					 * NOTE:
					 * 对于InvokeCache，key的类型为InvokeKey,
					 * 仅将InvokeKey的args字段暴露给调用层，不暴露InvokeKey对象本身
					 */
					key = (K) ((InvokeKey) notification.getKey()).args;
				}else {
					key = notification.getKey();
				}
				return new AocacheRemovalNotification<K, V>(key, notification.getValue(),
								AocacheRemovalCause.valueOf(notification.getCause()));

			}
			return null;
		}

		private AocacheRemovalNotification(K key, V value, AocacheRemovalCause cause) {
			super(key, value);
			this.cause = checkNotNull(cause);
		}

		public AocacheRemovalCause getCause() {
			return cause;
		}

		public boolean wasEvicted() {
			return cause.wasEvicted();
		}

		private static final long serialVersionUID = 0;
	}

	/** {@link com.google.common.cache.RemovalCause}的包装类 */
	public enum AocacheRemovalCause {
		EXPLICIT {
			@Override
			boolean wasEvicted() {
				return false;
			}
		},

		REPLACED {
			@Override
			boolean wasEvicted() {
				return false;
			}
		},

		COLLECTED {
			@Override
			boolean wasEvicted() {
				return true;
			}
		},

		EXPIRED {
			@Override
			boolean wasEvicted() {
				return true;
			}
		},

		SIZE {
			@Override
			boolean wasEvicted() {
				return true;
			}
		};

		abstract boolean wasEvicted();

		public static AocacheRemovalCause valueOf(RemovalCause cause) {
			return null == cause ? null : valueOf(cause.name());
		}
	}
}
